#pragma once

#include <stdint.h>

typedef int16_t         SHORT,      *PSHORT,    *LPSHORT;
typedef uint16_t        USHORT,     *PUSHORT,   *LPUSHORT;

typedef int32_t         INT,        *PINT,      *LPINT;
typedef uint32_t        UINT,       *PUINT,     *LPUINT;

typedef int32_t         LONG,       *PLONG,     *LPLONG;
typedef uint32_t        ULONG,      *PULONG,    *LPULONG;

typedef int8_t          BYTE,       *PBYTE,     *LPBYTE;
typedef uint16_t        WORD,       *PWORD,     *LPWORD;
typedef int32_t         DWORD,      *PDWORD,    *LPDOWRD;

typedef int64_t         LONGLONG,   *PLONGLONG;
typedef uint64_t        ULONGLONG,  *PULONGLONG;

// default pack
#pragma pack(push, 4)

#pragma pack(push, 2)
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
#pragma pack(pop)

#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory

#pragma pack(push, 2)
typedef struct _IMAGE_OPTIONAL_BASE_HEADER32 {
    //WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    DWORD       BaseOfData;
} IMAGE_OPTIONAL_BASE_HEADER32, *PIMAGE_OPTIONAL_BASE_HEADER32;
#pragma pack(pop)

typedef struct _IMAGE_OPTIONAL_NT_HEADER32 {
    DWORD       ImageBase;
    DWORD       SectionAlignment;
    DWORD       FileAlignment;
    WORD        MajorOperatingSystemVersion;
    WORD        MinorOperatingSystemVersion;
    WORD        MajorImageVersion;
    WORD        MinorImageVersion;
    WORD        MajorSubsystemVersion;
    WORD        MinorSubsystemVersion;
    DWORD       Win32VersionValue;
    DWORD       SizeOfImage;
    DWORD       SizeOfHeaders;
    DWORD       CheckSum;
    WORD        Subsystem;
    WORD        DllCharacteristics;
    DWORD       SizeOfStackReserve;
    DWORD       SizeOfStackCommit;
    DWORD       SizeOfHeapReserve;
    DWORD       SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_NT_HEADER32, *PIMAGE_OPTIONAL_NT_HEADER32;

#pragma pack(push, 2)
typedef struct _IMAGE_OPTIONAL_BASE_HEADER64 {
    //WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
} IMAGE_OPTIONAL_BASE_HEADER64, *PIMAGE_OPTIONAL_BASE_HEADER64;
#pragma pack(pop)

typedef struct _IMAGE_OPTIONAL_NT_HEADER64 {
    ULONGLONG   ImageBase;
    DWORD       SectionAlignment;
    DWORD       FileAlignment;
    WORD        MajorOperatingSystemVersion;
    WORD        MinorOperatingSystemVersion;
    WORD        MajorImageVersion;
    WORD        MinorImageVersion;
    WORD        MajorSubsystemVersion;
    WORD        MinorSubsystemVersion;
    DWORD       Win32VersionValue;
    DWORD       SizeOfImage;
    DWORD       SizeOfHeaders;
    DWORD       CheckSum;
    WORD        Subsystem;
    WORD        DllCharacteristics;
    ULONGLONG   SizeOfStackReserve;
    ULONGLONG   SizeOfStackCommit;
    ULONGLONG   SizeOfHeapReserve;
    ULONGLONG   SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_NT_HEADER64, *PIMAGE_OPTIONAL_NT_HEADER64;

typedef struct _IMAGE_NT_HEADERS32 {
    DWORD                           Signature;
    IMAGE_FILE_HEADER               FileHeader;
    WORD                            OptionalMagic;
    IMAGE_OPTIONAL_BASE_HEADER32    OptionalBase;
    IMAGE_OPTIONAL_NT_HEADER32      OptionalNt;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_NT_HEADERS64 {
    DWORD                           Signature;
    IMAGE_FILE_HEADER               FileHeader;
    WORD                            OptionalMagic;
    IMAGE_OPTIONAL_BASE_HEADER64    OptionalBase;
    IMAGE_OPTIONAL_NT_HEADER64      OptionalNt;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC       0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC       0x20b

#define IMAGE_SIZEOF_SHORT_NAME             8

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union
    {
        DWORD   PhysicalAddress;
        DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

#ifdef __x86_64__
#define IMAGE_NT_OPTIONAL_HDR_MAGIC     IMAGE_NT_OPTIONAL_HDR64_MAGIC

typedef IMAGE_OPTIONAL_BASE_HEADER64    IMAGE_OPTIONAL_BASE_HEADER, *PIMAGE_OPTIONAL_BASE_HEADER;
typedef IMAGE_OPTIONAL_NT_HEADER64      IMAGE_OPTIONAL_NT_HEADER, *PIMAGE_OPTIONAL_NT_HEADER;
typedef IMAGE_NT_HEADERS64              IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#else
#define IMAGE_NT_OPTIONAL_HDR_MAGIC     IMAGE_NT_OPTIONAL_HDR32_MAGIC

typedef IMAGE_OPTIONAL_BASE_HEADER32    IMAGE_OPTIONAL_BASE_HEADER, *PIMAGE_OPTIONAL_BASE_HEADER;
typedef IMAGE_OPTIONAL_NT_HEADER32      IMAGE_OPTIONAL_NT_HEADER, *PIMAGE_OPTIONAL_NT_HEADER;
typedef IMAGE_NT_HEADERS32              IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#endif

#pragma pack(pop)
